<!--
  Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.

  https://www.mall4j.com/

  未经允许，不可做商业用途！

  版权所有，侵权必究！
-->

<template>
  <view class="Mall4j htz-image-upload-list">
    <view
      v-for="(item, index) in uploadLists"
      :key="index"
      class="htz-image-upload-Item"
    >
      <view
        v-if="isVideo(item)"
        class="htz-image-upload-Item-video"
      >
        <!-- #ifndef APP-PLUS -->
        <video
          :disabled="false"
          :controls="false"
          :src="getFileUrl(item)"
        >
          <cover-view
            class="htz-image-upload-Item-video-fixed"
            @tap="previewVideo(getFileUrl(item))"
          />

          <cover-view
            v-if="remove && previewVideoSrc == ''"
            class="htz-image-upload-Item-del-cover"
            @tap="imgDel(index)"
          >×</cover-view>

        </video>
        <!-- #endif -->
        <!-- #ifdef APP-PLUS -->
        <view
          class="htz-image-upload-Item-video-fixed"
          @tap="previewVideo(getFileUrl(item))"
        />
        <image
          class="htz-image-upload-Item-video-app-poster"
          mode="widthFix"
          :src="util.checkFileUrl(appVideoPoster)"
        />
        <!-- #endif -->
      </view>

      <image
        v-else
        :src="getFileUrl(item)"
        mode="aspectFill"
        @tap="imgPreview(index)"
      />

      <view
        v-if="remove"
        class="htz-image-upload-Item-del"
        @tap="imgDel(index)"
      >
        ×
      </view>
    </view>
    <view
      v-if="uploadLists.length < max && add"
      class="htz-image-upload-Item htz-image-upload-Item-add"
      @tap="chooseFile"
    >
      +
    </view>
    <view
      v-if="previewVideoSrc != ''"
      class="preview-full"
    >
      <video
        :autoplay="true"
        :src="util.checkFileUrl(previewVideoSrc)"
        :show-fullscreen-btn="false"
      >
        <cover-view
          class="preview-full-close"
          @tap="previewVideoClose"
        > ×
        </cover-view>
      </video>
    </view>

    <!--  -->
  </view>
</template>

<script setup>
import util from '@/utils/util'
const emit = defineEmits([
  'input',
  'imgDelete',
  'chooseSuccess',
  'input',
  'uploadSuccess',
  'uploadFail',
  'uploadFail',
  'update:modelValue'
])

const props = defineProps({
  max: { // 展示图片最大值
    type: Number,
    default: 1
  },
  chooseNum: { // 选择图片数
    type: Number,
    default: 9
  },
  name: { // 发到后台的文件参数名
    type: String,
    default: 'file'
  },
  dataType: { // v-model的数据结构类型
    type: Number,
    default: 0 // 0: ['http://xxxx.jpg','http://xxxx.jpg'] 1:[{type:0,url:'http://xxxx.jpg'}]  type 0 图片 1 视频 url 文件地址 此类型是为了给没有文件后缀的状况使用的
  },
  remove: { // 是否展示删除按钮
    type: Boolean,
    default: true
  },
  add: { // 是否展示添加按钮
    type: Boolean,
    default: true
  },
  disabled: { // 是否禁用
    type: Boolean,
    default: false
  },
  sourceType: { // 选择照片来源 【ps：H5就别费劲了，设置了也没用。不是我说的，官方文档就这样！！！】
    type: Array,
    default: () => ['album', 'camera']
  },
  action: { // 上传地址 如需使用uniCloud服务，设置为uniCloud即可
    type: String,
    default: ''
  },
  headers: { // 上传的请求头部
    type: Object,
    default: () => { }
  },
  formData: { // HTTP 请求中其他额外的 form data
    type: Object,
    default: () => { }
  },
  compress: { // 是否需要压缩
    type: Boolean,
    default: true
  },
  quality: { // 压缩质量，范围0～100
    type: Number,
    default: 80
  },
  modelValue: { // 受控图片列表
    type: Array,
    default: () => []
  },
  // eslint-disable-next-line vue/require-prop-types
  uploadSuccess: {
    default: () => {
      return {
        success: false,
        url: ''
      }
    }
  },
  mediaType: { // 文件类型 image/video/all
    type: String,
    default: 'image'
  },
  maxDuration: { // 拍摄视频最长拍摄时间，单位秒。最长支持 60 秒。 (只针对拍摄视频有用)
    type: Number,
    default: 60
  },
  camera: { // 'front'、'back'，默认'back'(只针对拍摄视频有用)
    type: String,
    default: 'back'
  },
  appVideoPoster: { // app端视频展示封面 只对app有效
    type: String,
    default: '/static/htz-image-upload/play.png'
  }
})

const Data = reactive({
  uploadLists: [],
  mediaTypeData: ['image', 'video', 'all'],
  previewVideoSrc: ''
})

const { uploadLists, previewVideoSrc } = toRefs(Data)

watch(() => props.modelValue, (val) => {
  Data.uploadLists = val
})

onMounted(() => {
  nextTick(function () {
    Data.uploadLists = props.modelValue
    if (Data.mediaTypeData.indexOf(props.mediaType) == -1) {
      uni.showModal({
        title: '提示',
        content: 'mediaType参数不正确',
        showCancel: false
      })
    }
  })
})

const isVideo = (item) => {
  let isPass = false
  if ((!/.(gif|jpeg|jpg|png|webp)$/i.test(item) && props.dataType == 0) || (props.dataType == 1 && item
    .type == 1)) {
    isPass = true
  }
  return isPass
}
const getFileUrl = (item) => {
  let url = item
  if (props.dataType == 1) {
    url = item.url
  }
  return util.checkFileUrl(url)
}
const previewVideo = (src) => {
  Data.previewVideoSrc = src
}
const previewVideoClose = () => {
  Data.previewVideoSrc = ''
}
const imgDel = (index) => {
  const delUrl = Data.uploadLists[index]
  Data.uploadLists.splice(index, 1)
  emit('update:modelValue', Data.uploadLists)
  emit('imgDelete', {
    del: delUrl,
    tempFilePaths: Data.uploadLists
  })
}
const imgPreview = (index) => {
  const imgData = []

  Data.uploadLists.forEach((item) => {
    if (!isVideo(item)) {
      imgData.push(getFileUrl(item))
    }
  })

  uni.previewImage({
    urls: imgData,
    current: index,
    loop: true
  })
}
const chooseFile = () => {
  if (props.disabled) {
    return false
  }
  switch (Data.mediaTypeData.indexOf(props.mediaType)) {
    case 1: // 视频
      videoAdd()
      break
    case 2: // 全部
      uni.showActionSheet({
        itemList: ['相册', '视频'],
        success: (res) => {
          if (res.tapIndex == 1) {
            videoAdd()
          } else if (res.tapIndex == 0) {
            imgAdd()
          }
        },
        fail: () => {
        }
      })
      break
    default: // 图片
      imgAdd()
      break
  }
}
const videoAdd = () => {
  uni.chooseVideo({
    compressed: props.compress,
    sourceType: props.sourceType,
    camera: props.camera,
    maxDuration: props.maxDuration,
    success: (res) => {
      chooseSuccessMethod([res.tempFilePath], res)
    }
  })
}
const imgAdd = () => {
  // console.log('imgAdd')
  const nowNum = Math.abs(Data.uploadLists.length - props.max)
  const thisNum = (props.chooseNum > nowNum ? nowNum : props.chooseNum) // 可选数量
  // #ifdef APP-PLUS
  if (props.sourceType.length > 1) {
    uni.showActionSheet({
      itemList: ['拍摄', '从手机相册选择'],
      success: (res) => {
        if (res.tapIndex == 1) {
          appGallery(thisNum)
        } else if (res.tapIndex == 0) {
          appCamera()
        }
      },
      fail: () => {
      }
    })
  }
  if (props.sourceType.length == 1 && props.sourceType.indexOf('album') > -1) {
    appGallery(thisNum)
  }

  if (props.sourceType.length == 1 && props.sourceType.indexOf('camera') > -1) {
    appCamera()
  }
  // #endif
  // #ifndef APP-PLUS
  uni.chooseImage({
    count: thisNum,
    sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图，默认二者都有
    sourceType: props.sourceType,
    success: (res) => {
      chooseSuccessMethod(res.tempFilePaths, res)
    }
  })
  // #endif
}
const appCamera = () => {
  const cmr = plus.camera.getCamera()
  const res = cmr.supportedImageResolutions[0]
  const fmt = cmr.supportedImageFormats[0]
  cmr.captureImage((path) => {
    chooseSuccessMethod([path], 0)
  },
  () => {
  }, {
    resolution: res,
    format: fmt
  }
  )
}
const appGallery = (maxNum) => {
  plus.gallery.pick((res) => {
    chooseSuccessMethod(res.files, 0)
  }, function () {
  }, {
    filter: 'image',
    multiple: true,
    maximum: maxNum
  })
}
const chooseSuccessMethod = (filePaths, type) => {
  if (props.action == '') { // 未配置上传路径
    emit('chooseSuccess', filePaths, type) // filePaths 路径 type 0 为图片 1为视频
  } else {
    if (type == 1) {
      imgUpload(filePaths, type)
    } else {
      if (props.compress) { // 设置了需要压缩
        imgCompress(filePaths, type)
      } else {
        imgUpload(filePaths, type)
      }
    }
  }
}
const imgCompress = (tempFilePaths, type) => { // type 0 为图片 1为视频
  uni.showLoading({
    title: '压缩中...'
  })

  const compressImgs = []
  const results = []
  tempFilePaths.forEach((item) => {
    compressImgs.push(new Promise((resolve, reject) => {
      // #ifndef H5
      uni.compressImage({
        src: item,
        quality: props.quality,
        success: res => {
          results.push(res.tempFilePath)
          resolve(res.tempFilePath)
        },
        fail: (err) => {
          reject(err)
        },
        complete: () => {
        }
      })
      // #endif
      // #ifdef H5
      canvasDataURL(item, {
        quality: props.quality / 100
      }, (base64Codes) => {
        results.push(base64Codes)
        resolve(base64Codes)
      })
      // #endif
    }))
  })
  Promise.all(compressImgs) // 执行所有需请求的接口
    .then((results) => {
      uni.hideLoading()
      imgUpload(results, type)
    })
    .catch(() => {
      uni.hideLoading()
    })
}
const imgUpload = (tempFilePaths, type) => { // type 0 为图片 1为视频
  if (props.action == 'uniCloud') {
    uniCloudUpload(tempFilePaths, type)
    return
  }
  uni.showLoading({
    title: '上传中'
  })
  const uploadImgs = []
  tempFilePaths.forEach((item) => {
    uploadImgs.push(new Promise((resolve, reject) => {
      uni.uploadFile({
        url: props.action, // 仅为示例，非真实的接口地址
        filePath: item,
        name: props.name,
        fileType: 'image',
        formData: props.formData,
        header: props.headers,
        success: (uploadFileRes) => {
          // uni.hideLoading();
          // console.log(typeof uploadSuccess)
          // console.log('')
          uploadFileRes.fileType = type
          if (typeof props.uploadSuccess === 'function') {
            const thisUploadSuccess = props.uploadSuccess(uploadFileRes)
            if (thisUploadSuccess.success) {
              if (props.dataType == 0) {
                // eslint-disable-next-line vue/no-mutating-props
                props.modelValue.push(thisUploadSuccess.url)
              } else {
                // eslint-disable-next-line vue/no-mutating-props
                props.modelValue.push({
                  type,
                  url: thisUploadSuccess.url
                })
              }

              emit('update:modelValue', Data.uploadLists)
            }
          }
          resolve(uploadFileRes)
          emit('uploadSuccess', uploadFileRes)
        },
        fail: (err) => {
          reject(err)
          emit('uploadFail', err)
        },
        complete: () => {
        }
      })
    }))
  })
  Promise.all(uploadImgs) // 执行所有需请求的接口
    .then(() => {
      uni.hideLoading()
    })
    .catch((res) => {
      uni.hideLoading()
      emit('uploadFail', res)
    })
}
const uniCloudUpload = (tempFilePaths, type) => {
  uni.showLoading({
    title: '上传中'
  })
  const uploadImgs = []
  tempFilePaths.forEach((item) => {
    uploadImgs.push(new Promise((resolve, reject) => {
      // eslint-disable-next-line no-undef
      uniCloud.uploadFile({
        filePath: item,
        cloudPath: guid() + '.' + getFileType(item, type),
        success (uploadFileRes) {
          if (uploadFileRes.success) {
            resolve(uploadFileRes.fileID)
          }
        },
        fail (err) {
          reject(err)
        },
        complete () { }
      })
    }))
  })
  Promise.all(uploadImgs) // 执行所有需请求的接口
    .then((results) => {
      uni.hideLoading()
      // eslint-disable-next-line no-undef
      uniCloud.getTempFileURL({
        fileList: results,
        success: (res) => {
          res.fileList.forEach(item => {
            // eslint-disable-next-line vue/no-mutating-props
            props.modelValue.push(item.tempFileURL)
          })
        },
        fail () { },
        complete () { }
      })
    })
    .catch(() => {
      uni.hideLoading()
    })
}
const getFileType = (path, type) => { // 手机端默认图片为jpg 视频为mp4
  let result = null
  // #ifdef H5
  result = type == 0 ? 'jpg' : 'mp4'
  // #endif

  // #ifndef H5
  // eslint-disable-next-line no-redeclare
  result = path.split('.').pop().toLowerCase()
  // #ifdef MP
  if (props.compress) { // 微信小程序压缩完没有后缀
    result = type == 0 ? 'jpg' : 'mp4'
  }
  // #endif
  // #endif
  return result
}
const guid = () => {
  return 'xxxxxxxx-date-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    const r = Math.random() * 16 | 0
    const v = c == 'x' ? r : (r & 0x3 | 0x8)
    return v.toString(16)
  }).replace(/date/g, function () {
    return Date.parse(new Date())
  })
}

const { proxy } = getCurrentInstance()
const canvasDataURL = (path, obj, callback) => {
  const img = new Image()
  img.src = path
  img.onload = function () {
    // 默认按比例压缩
    let w = props.width
    let h = props.height
    const scale = w / h
    w = obj.width || w
    h = obj.height || (w / scale)
    let quality = 0.8 // 默认图片质量为0.8
    // 生成canvas
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    // 创建属性节点
    const anw = document.createAttribute('width')
    anw.nodeValue = w
    const anh = document.createAttribute('height')
    anh.nodeValue = h
    canvas.setAttributeNode(anw)
    canvas.setAttributeNode(anh)
    ctx.drawImage(proxy, 0, 0, w, h)
    // 图像质量
    if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
      quality = obj.quality
    }
    // quality值越小，所绘制出的图像越模糊
    const base64 = canvas.toDataURL('image/jpeg', quality)
    // 回调函数返回base64的值
    callback(base64)
  }
}

</script>

<!-- eslint-disable-next-line vue-scoped-css/enforce-style-type -->
<style>
.ceshi {
  width: 100%;
  height: 100%;
  position: relative;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background-color: #FFFFFF;
  color: #2C405A;
  opacity: 0.5;
  z-index: 100;
}
</style>
<!-- eslint-disable-next-line vue-scoped-css/enforce-style-type -->
<style>
.preview-full {

  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  z-index: 1002;
}

.preview-full video {

  width: 100%;
  height: 100%;
  z-index: 1002;
}

.preview-full-close {
  position: fixed;
  right: 32rpx;
  top: 25rpx;
  width: 80rpx;
  height: 80rpx;
  line-height: 60rpx;
  text-align: center;
  z-index: 1003;
  /*   background-color: #808080; */
  color: #fff;
  font-size: 65rpx;
  font-weight: bold;
  text-shadow: 1px 2px 5px rgb(0 0 0);
}

/* .preview-full-close-before,
  .preview-full-close-after {
    position: absolute;
    top: 50%;
    left: 50%;
    content: '';
    height: 60rpx;
    margin-top: -30rpx;
    width: 6rpx;
    margin-left: -3rpx;
    background-color: #FFFFFF;
    z-index: 20000;
  }

  .preview-full-close-before {
    transform: rotate(45deg);

  }

  .preview-full-close-after {
    transform: rotate(-45deg);

  } */

.htz-image-upload-list {
  /* overflow-x: auto; */
  /* max-width: 1830rpx; */
  display: flex;
  /* flex-wrap: wrap; */
}

.htz-image-upload-Item {

  flex-shrink: 0;
  width: 180rpx;
  height: 180rpx;
  margin: 13rpx;
  border-radius: 10rpx;
  position: relative;
}

.htz-image-upload-Item image {
  width: 100%;
  height: 100%;
  border-radius: 10rpx;
}

.htz-image-upload-Item-video {
  width: 100%;
  height: 100%;
  border-radius: 10rpx;
  position: relative;

}

.htz-image-upload-Item-video-fixed {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  border-radius: 10rpx;
  z-index: 996;

}

.htz-image-upload-Item video {
  width: 100%;
  height: 100%;
  border-radius: 10rpx;

}

.htz-image-upload-Item-add {
  font-size: 66rpx;
  line-height: 160rpx;
  text-align: center;
  border: 1px solid #d9d9d9;
  color: #999999;
}

.htz-image-upload-Item-del {

  background: rgba(0, 0, 0, 0.39);
  font-size: 20rpx;
  position: absolute;
  width: 36rpx;
  height: 36rpx;

  border-radius: 0 10rpx 0 25rpx;
  line-height: 36rpx;
  text-align: center;
  top: 0;
  right: 0;
  z-index: 997;
  color: #fff;
}

.htz-image-upload-Item-del-cover {
  background: rgba(0, 0, 0, 0.39);
  font-size: 20rpx;
  position: absolute;
  width: 36rpx;
  height: 36rpx;

  border-radius: 0 10rpx 0 25rpx;
  line-height: 36rpx;
  text-align: center;
  top: 0;
  right: 0;
  z-index: 997;
  color: #fff;

}

.htz-image-upload-Item-video-app-poster {
  width: 100%;
  height: 100%;
}
</style>
